package ru.amse.jsynchro.kernel.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import ru.amse.jsynchro.fileSystem.FileSystem;

public class FileSystemUtil {
    /**
     * makes a new folder which will contain such elements as in
     * <code>dir</code>
     * <code>destin</code> must not exist
     * 
     * @param dir
     *            a folder which will be copied
     * @param destin
     *            a result folder of copy. <code>destin</code> must not exist
     */

    public static boolean copyDirR(File dir, FileSystem fs1, File destin,
            FileSystem fs2) {
        // if (!destin.mkdir()) {
        // throw new AssertionError("can't create folder: " + destin.getPath());
        // }
        try {
            fs2.makeDir(destin);

            File[] childs = fs1.listFiles(dir);
            for (File f : childs) {
                if (f.isFile()) {
                    // System.out.println(f.getPath() + " file");
                    if (!copyFile(f, fs1, new File(destin, f.getName()), fs2)) {
                        return false;
                    }
                } else {
                    if (!copyDirR(f, fs1, new File(destin, f.getName()), fs2)) {
                        return false;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    public static boolean copyDir(File dir, FileSystem fs1, File destin,
            FileSystem fs2) {
        // if (!destin.mkdir()) {
        // throw new AssertionError("can't create folder: " + destin.getPath());
        // }
        try {
            fs2.makeDir(destin);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * creates a copy of a file
     * 
     * @param source
     *            the {@code File}, which copy will be created
     * @param destin
     *            the {@code File}, a copy of {@code} source
     * @return true if succeed
     */
    public static boolean copyFile(File source, FileSystem sourceFS,
            File destin, FileSystem destinationFS) {
        if (source.equals(destin)) {
            throw new IllegalArgumentException(
                    "source and destination files are equal: "
                            + source.getPath());
        }
        InputStream in = null;
        OutputStream out = null;
        try {
            long fileLength = sourceFS.getFileLength(source.getAbsolutePath());
            in = sourceFS.openInputStream(source.getAbsolutePath(), fileLength);
            if (destin.isDirectory()) {
                deleteDirR(destin, destinationFS);
            }
            out = destinationFS.openOutputStream(destin
                    .getAbsolutePath(), fileLength);
            int c = 0;
            while ((c = in.read()) >= 0) {
                out.write(c);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                sourceFS.closeInputStream(in);
                destinationFS.closeOutputStream(out);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * recursive deletes a folder and it's subelements
     * 
     * @param dir
     *            a directory to delete
     * @return true if succeed
     */
    public static boolean deleteDirR(File dir, FileSystem fs) {
        try {
            File[] childs = fs.listFiles(dir);
            for (File f : childs) {
                if (f.isFile()) {
                    // if (!f.delete()) {
                    // return false;
                    // }
                    fs.deleteFile(f);
                } else {
                    if (!deleteDirR(f, fs)) {
                        return false;
                    }
                }
            }
            dir.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    // is not invoked
    public static boolean deleteDir(File dir) {
        return dir.delete();
    }

    public static void readErrorStream(File sourceFile, FileSystem sourceFS) {

    }

}
